﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using FarseerPhysics.Dynamics;

namespace SpriteGame.Rendering
{
    public class ShapeRenderer
    {
        GraphicsDevice graphics;

        BasicEffect effect;
        short[] indexData;

        VertexPositionNormalTexture[] vertexData;

        VertexDeclaration vertexDeclaration;

        Game1 parentGame;

        static Vector3 NORMAL = Vector3.Forward;

        static float LEVEL;

        int drawCount;
        const int MAXDRAW = 100;

        public ShapeRenderer(GraphicsDevice _graphics, Game1 _parent)
        {
            parentGame = _parent;
            graphics = _graphics;
        }

        public void LoadContent()
        {
            effect = new BasicEffect(graphics);

            vertexData = new VertexPositionNormalTexture[FarseerPhysics.Common.Settings.MaxPolygonVertices];
            indexData = new short[6];

            int width = 1, height = 1;

            vertexData[0] = new VertexPositionNormalTexture(
                        new Vector3(0, 0, LEVEL), NORMAL, new Vector2(0, 1));
            vertexData[1] = new VertexPositionNormalTexture(
                        new Vector3(0, height, LEVEL), NORMAL, new Vector2(0, 0));
            vertexData[2] = new VertexPositionNormalTexture(
                        new Vector3(width, 0, LEVEL), NORMAL, new Vector2(1, 1));
            vertexData[3] = new VertexPositionNormalTexture(
                        new Vector3(width, height, LEVEL), NORMAL, new Vector2(1, 0));

            indexData[0] = 0;
            indexData[1] = 1;
            indexData[2] = 2;
            indexData[3] = 2;
            indexData[4] = 1;
            indexData[5] = 3;

            vertexDeclaration = VertexPositionNormalTexture.VertexDeclaration;
        }

        public void BeginBatch()
        {
            LEVEL = 0.0f;
            drawCount = 0;
            effect.World = Matrix.Identity;

            effect.Projection = parentGame.Projection;
            effect.TextureEnabled = true;
            //graphics.RenderState.FillMode = FillMode.WireFrame;
            //effect.EnableDefaultLighting();
            //graphics.VertexDeclaration = vertexDeclaration;
            //effect.();
        }

        public void EndBatch()
        {
            //effect.End();
        }

        void setHeightWidth(float _height, float _width)
        {
            vertexData[0].Position = new Vector3(0, 0, LEVEL);
            vertexData[1].Position = new Vector3(0, _height, LEVEL);
            vertexData[2].Position = new Vector3(_width, 0, LEVEL);
            vertexData[3].Position = new Vector3(_width, _height, LEVEL);

            vertexData[0].TextureCoordinate = new Vector2(0, 1);
            vertexData[1].TextureCoordinate = new Vector2(0, 0);
            vertexData[2].TextureCoordinate = new Vector2(1, 1);
            vertexData[3].TextureCoordinate = new Vector2(1, 0);
        }

        void setHeightWidthOffset(float x1, float x2, float _height, float _width)
        {
            vertexData[0].Position = new Vector3(0, 0, LEVEL);
            vertexData[1].Position = new Vector3(0, _height, LEVEL);
            vertexData[2].Position = new Vector3(_width, 0, LEVEL);
            vertexData[3].Position = new Vector3(_width, _height, LEVEL);

            vertexData[0].TextureCoordinate = new Vector2(x1, 1);
            vertexData[1].TextureCoordinate = new Vector2(x1, 0);
            vertexData[2].TextureCoordinate = new Vector2(x2, 1);
            vertexData[3].TextureCoordinate = new Vector2(x2, 0);
        }

        void setHeightWidthOffset(float x1, float x2, float _height, float _width, bool _flip)
        {
            vertexData[0].Position = new Vector3(0, 0, LEVEL);
            vertexData[1].Position = new Vector3(0, _height, LEVEL);
            vertexData[2].Position = new Vector3(_width, 0, LEVEL);
            vertexData[3].Position = new Vector3(_width, _height, LEVEL);

            if (_flip)
            {
                vertexData[0].TextureCoordinate = new Vector2(x2, 1);
                vertexData[1].TextureCoordinate = new Vector2(x2, 0);
                vertexData[2].TextureCoordinate = new Vector2(x1, 1);
                vertexData[3].TextureCoordinate = new Vector2(x1, 0);
            }
            else
            {
                vertexData[0].TextureCoordinate = new Vector2(x1, 1);
                vertexData[1].TextureCoordinate = new Vector2(x1, 0);
                vertexData[2].TextureCoordinate = new Vector2(x2, 1);
                vertexData[3].TextureCoordinate = new Vector2(x2, 0);
            }
        }

        //void setAnimatedHeightWidth(float _height, float _width, int _frame, int _frames)
        //{
        //    vertexData[0].Position = new Vector3(0, 0, LEVEL);
        //    vertexData[1].Position = new Vector3(0, _height, LEVEL);
        //    vertexData[2].Position = new Vector3(_width, 0, LEVEL);
        //    vertexData[3].Position = new Vector3(_width, _height, LEVEL);

        //    vertexData[0].TextureCoordinate = new Vector2(0, 1);
        //    vertexData[1].TextureCoordinate = new Vector2(0, 0);
        //    vertexData[2].TextureCoordinate = new Vector2((1.0f/_frames)*_frame, 1);
        //    vertexData[3].TextureCoordinate = new Vector2((1.0f / _frames) * _frame, 0);
        //}

        public void DrawCustomShape(Vector2 _position, Vector2[] _vertices, Texture2D _texture, bool _textureWarp)
        {
            if (drawCount > MAXDRAW)
            {
                EndBatch();
                BeginBatch();
            }
            vertexData[0].Position = new Vector3(_vertices[0], LEVEL);
            vertexData[1].Position = new Vector3(_vertices[1], LEVEL);
            vertexData[2].Position = new Vector3(_vertices[2], LEVEL);
            vertexData[3].Position = new Vector3(_vertices[3], LEVEL);

            if (!_textureWarp)
            {

                vertexData[0].TextureCoordinate = _vertices[0] / _texture.Width;
                vertexData[1].TextureCoordinate = _vertices[1] / -_texture.Width;
                vertexData[2].TextureCoordinate = _vertices[2] / _texture.Width;
                vertexData[3].TextureCoordinate = _vertices[3] / _texture.Width;
                vertexData[3].TextureCoordinate.Y *= -1;
            }

            effect.Texture = _texture;
            effect.World = Matrix.CreateTranslation(new Vector3(_position, 0));

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphics.DrawUserIndexedPrimitives
                    <VertexPositionNormalTexture>(
                    PrimitiveType.TriangleList,
                    vertexData, 0, 4,
                    indexData, 0, 2);
                //pass.End();
            }

            LEVEL += 0.01f;
            drawCount++;
        }

        public void DrawAnimatedQuad(int numFrames, int frame, Vector2 _position, float _rotation, float _width, float _height, Texture2D _texture, bool flip)
        {
            float frameWidth = 1.0f / (float)numFrames;

            float start = frameWidth * frame;
            frame++;
            float end = frameWidth * frame;

            if (drawCount > MAXDRAW)
            {
                EndBatch();
                BeginBatch();
            }

            setHeightWidthOffset(start,end,_height, _width, flip);

            effect.Texture = _texture;
            effect.World = Matrix.CreateTranslation(new Vector3(-_width * 0.5f, -_height * 0.5f, 0)) * Matrix.CreateRotationZ(_rotation) * Matrix.CreateTranslation(new Vector3(_position, 0));

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphics.DrawUserIndexedPrimitives
                    <VertexPositionNormalTexture>(
                    PrimitiveType.TriangleList,
                    vertexData, 0, 4,
                    indexData, 0, 2);
                //graphics.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
                //    vertexData, 0, 1);
                //pass.End();
            }

            drawCount++;
            LEVEL += 0.01f;
        }

        public void DrawQuad(Vector2 _position, float _rotation, float _width, float _height, Texture2D _texture)
        {
            if (drawCount > MAXDRAW)
            {
                EndBatch();
                BeginBatch();
            }

            setHeightWidth(_height, _width);

            effect.Texture = _texture;
            effect.World = Matrix.CreateTranslation(new Vector3(-_width * 0.5f, -_height * 0.5f, 0)) * Matrix.CreateRotationZ(_rotation) * Matrix.CreateTranslation(new Vector3(_position, 0));

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphics.DrawUserIndexedPrimitives
                    <VertexPositionNormalTexture>(
                    PrimitiveType.TriangleList,
                    vertexData, 0, 4,
                    indexData, 0, 2);
                //graphics.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
                //    vertexData, 0, 1);
                //pass.End();
            }

            drawCount++;
            LEVEL += 0.01f;
        }

        public void DrawQuad(Matrix _transforms, float _width, float _height, Texture2D _texture)
        {
            if (drawCount > MAXDRAW)
            {
                EndBatch();
                BeginBatch();
            }

            setHeightWidth(_height, _width);

            effect.Texture = _texture;
            effect.World = _transforms;

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphics.DrawUserIndexedPrimitives
                    <VertexPositionNormalTexture>(
                    PrimitiveType.TriangleList,
                    vertexData, 0, 4,
                    indexData, 0, 2);
                //graphics.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
                //    vertexData, 0, 1);
                //pass.End();
            }

            drawCount++;
            LEVEL += 0.01f;
        }

        public void DrawBody(Body _body, Texture2D _texture)
        {

        }

        public void DrawQuad(Vector2 _position, Texture2D _texture)
        {
            //effect.World = World;
            //effect.View = View;
            //effect.Projection = Projection;

            if (drawCount > MAXDRAW)
            {
                EndBatch();
                BeginBatch();
            }

            int height = _texture.Height;
            int width = _texture.Width;

            setHeightWidth(height, width);

            effect.Texture = _texture;
            effect.World = Matrix.CreateTranslation(new Vector3(-width * 0.5f, -height * 0.5f, 0)) * Matrix.CreateTranslation(new Vector3(_position, 0));

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphics.DrawUserIndexedPrimitives
                    <VertexPositionNormalTexture>(
                    PrimitiveType.TriangleList,
                    vertexData, 0, 4,
                    indexData, 0, 2);
                //pass.End();
            }

            LEVEL += 0.01f;
            drawCount++;
        }

        public void DrawQuad(Matrix _transform, Texture2D _texture)
        {
            //effect.World = World;
            //effect.View = View;
            //effect.Projection = Projection;

            if (drawCount > MAXDRAW)
            {
                EndBatch();
                BeginBatch();
            }

            setHeightWidth(_texture.Height, _texture.Width);

            effect.Texture = _texture;
            effect.World = _transform;

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphics.DrawUserIndexedPrimitives
                    <VertexPositionNormalTexture>(
                    PrimitiveType.TriangleList,
                    vertexData, 0, 4,
                    indexData, 0, 2);
                //pass.End();
            }

            LEVEL += 0.01f;
            drawCount++;
        }

        //public void DrawQuad(Vector2 _position, Vector2 _origin, float _rotation, Texture2D _texture)
        //{
        //    //effect.World = World;
        //    //effect.View = View;
        //    //effect.Projection = Projection;

        //    setHeightWidth(_texture.Height, _texture.Width);

        //    effect.Texture = _texture;
        //    effect.World = Matrix.CreateTranslation(-(new Vector3(_origin, 0))) * Matrix.CreateTranslation(new Vector3(_position, 0)) * Matrix.CreateRotationZ(_rotation);

        //    foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        //    {
        //        pass.Begin();
        //        graphics.DrawUserIndexedPrimitives
        //            <VertexPositionNormalTexture>(
        //            PrimitiveType.TriangleList,
        //            vertexData, 0, 4,
        //            indexData, 0, 2);
        //        pass.End();
        //    }

        //    LEVEL += 0.01f;
        //}
    }
}
